/*
 *  Copyright (C) 2010 Zubanov Dmitry
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 *
 * @author Zubanov Dmitry aka javadimon, zubanov@gmail.com
 * Omsk, Russia, created 29.05.2010
 * (C) Copyright by Zubanov Dmitry
 */
package org.jssdb.core.handler;

import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jssdb.core.DBHandler;
import org.jssdb.core.DBProperties;
import org.jssdb.core.filesystem.FilesListInfo;
import org.jssdb.core.utils.FileInfo;
import org.jssdb.core.utils.MetaInfoData;
import org.jssdb.core.utils.SizeException;

/**
 *
 * @author Zubanov Dmitry aka javadimon, zubanov@gmail.com
 * Omsk, Russia,
 * created 08.05.2010
 */
public class Handler implements DBHandler {

    private static Handler self = null;
    private FileStorageHandler fsh;
    private SerializableHandler sh;
    private DeserializableHandler dh;
    private static final Object sync = new Object();
    private static final Logger logger = Logger.getLogger(Handler.class.getName());

    private Handler() {
        fsh = FileStorageHandler.getDefault();
        sh = SerializableHandler.getDefault();
        dh = DeserializableHandler.getDefault();
    }

    public static Handler getInstance() {
        if (self == null) {
            self = new Handler();
        }

        return self;
    }

    @Override
    public long add(Object obj) {
        if (obj == null) {
            return -1;
        }
        File f = new File(DBProperties.getInstance().getPathToDB() + obj.getClass().getName());
        if (!f.isDirectory()) {
            f.mkdir();
        }

        synchronized (sync) {
            FileInfo fInfo = fsh.getSaveFileInfo(f);
            long id = sh.serialaizable(fInfo, obj);
            if (id != -1) {
                FilesListInfo.getInstance().addNewFileInfo(fInfo.getFileName());
            }
            return id;
        }
    }

    public long add(long id, Object obj) {
        long result = -1;
        String strDir = DBProperties.getInstance().getPathToDB() + obj.getClass().getName();
        File f = new File(strDir);
        if (!f.isDirectory()) {
            f.mkdir();
        }

        FileInfo fi = new FileInfo(strDir + File.separator + id, id);
        result = sh.serialaizable(fi, obj);
        FilesListInfo.getInstance().addNewFileInfo(fi.getFileName());
        return result;
    }

    public void add(long id, long lastModified, Object obj) {
        String strDir = DBProperties.getInstance().getPathToDB() + obj.getClass().getName();
        File f = new File(strDir);
        if (!f.isDirectory()) {
            f.mkdir();
        }

        FileInfo fi = new FileInfo(strDir + File.separator + id, id);
        sh.serialaizable(fi, obj);

        File fUpdate = new File(fi.getFileName());
        fUpdate.setLastModified(lastModified);
        FilesListInfo.getInstance().addNewFileInfo(fi.getFileName());
    }

    @Override
    public Object get(long id, Class cls) {
        String fileName = fsh.getLoadFile(id, cls);
        if (fileName == null) {
            return null;
        }

        return dh.deserialaizable(fileName);
    }

    @Override
    public Object get(long id, String className) {
        Class cls = null;
        Object obj = null;
        try {
            cls = Class.forName(className);
        } catch (ClassNotFoundException ex) {
            logger.log(Level.SEVERE, className, ex);
        }

        obj = get(id, cls);

        return obj;
    }

    @Override
    public boolean update(long id, Object obj) {
        boolean result = false;
        if (obj == null) {
            return result;
        }

        String fileName = fsh.getLoadFile(id, obj.getClass());
        if (fileName == null) {
            return result;
        }

        synchronized (sync) {
            result = sh.serialaizable(fileName, obj);
            if (result) {
                FilesListInfo.getInstance().modifyFileInfo(fileName);
            }
        }

        return result;
    }

    @Override
    public boolean delete(long id, String className) {
        boolean result = false;
        if (className == null) {
            return false;
        }

        synchronized (sync) {
            result = fsh.deleteFile(id, className);
            if (result) {
                FilesListInfo.getInstance().deleteFileInfo(className, id);
            }
        }

        return result;
    }

    @Override
    public boolean delete(long id, Class cls) {
        boolean result = false;
        if (cls == null) {
            return result;
        }

        synchronized (sync) {
            result = fsh.deleteFile(id, cls);
            if (result) {
                FilesListInfo.getInstance().deleteFileInfo(cls.getName(), id);
            }
        }

        return result;
    }

    @Override
    public ArrayList<Map<Long, Object>> getCollection(long idFrom, long idTo, String className) throws SizeException {
        ArrayList<Map<Long, Object>> list = null;
        list = dh.getCollection(fsh.getFileList(idFrom, idTo, className));

        return list;
    }

    @Override
    public ArrayList<Map<Long, Object>> getCollection(String className) throws SizeException {
        ArrayList<Map<Long, Object>> list = null;
        list = dh.getCollection(fsh.getAllFilesList(className));
        return list;
    }

    @Override
    public ArrayList<Map<Long, Object>> getCollection(Class cls) throws SizeException {
        ArrayList<Map<Long, Object>> list = null;
        list = getCollection(cls.getName());
        return list;
    }

    @Override
    public ArrayList<Map<Long, Object>> getCollection(long idFrom, long idTo, Class cls) throws SizeException {

        ArrayList<Map<Long, Object>> list = null;
        list = dh.getCollection(fsh.getFileList(idFrom, idTo, cls));
        return list;
    }

    @Override
    public long getMinId(String className) {
        return fsh.getMinId(className);
    }

    @Override
    public long getMinId(Class cls) {
        return fsh.getMinId(cls);
    }

    @Override
    public long getMaxId(String className) {
        return fsh.getMaxId(className);
    }

    @Override
    public long getMaxId(Class cls) {
        return fsh.getMaxId(cls);
    }

    @Override
    public MetaInfoData getMetaInfo(long id, Class cls) {
        return MetaInfo.getDefault().getMetaInfo(id, cls);
    }
}
